#pragma once

#undef _WIN32
#include "spdlog/spdlog.h"
#define _WIN32

#include <memory>

#ifndef __FUNC__
#ifdef __GNUC__
#define __FUNC__ __PRETTY_FUNCTION__
#else
#define __FUNC__ __FUNCTION__
#endif
#endif

#ifndef __FLF__
#define __FLF__ __FILE__, __LINE__, __FUNC__
#endif

namespace rewine
{

class Logger {
private:

    std::shared_ptr<spdlog::logger> m_Logger;

private:

    template<typename... Args>
    void log(int level, const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        m_Logger->log(static_cast<spdlog::level::level_enum>(level), fmt, args...);
    }

public:

    Logger();
    ~Logger();

    template<typename... Args>
    void trace(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::trace, file, line, func, fmt, args...);
    }

    template<typename... Args>
    void debug(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::debug, file, line, func, fmt, args...);
    }

    template<typename... Args>
    void info(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::info, file, line, func, fmt, args...);
    }

    template<typename... Args>
    void warning(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::warn, file, line, func, fmt, args...);
    }

    template<typename... Args>
    void error(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::err, file, line, func, fmt, args...);
    }

    template<typename... Args>
    void fatal(const char *file, int line, const char *func, const char *fmt, const Args &...args) {
        log(spdlog::level::critical, file, line, func, fmt, args...);
    }

    void onTrace() {
        spdlog::set_level(spdlog::level::trace);
    }

    void onDebug() {
        spdlog::set_level(spdlog::level::debug);
    }

    void onInfo() {
        spdlog::set_level(spdlog::level::info);
    }

    void onWarning() {
        spdlog::set_level(spdlog::level::warn);
    }

    void onError() {
        spdlog::set_level(spdlog::level::err);
    }

};

} // namespace rewine
